package xfuzzy.xfghl.population;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import xfuzzy.xfghl.codification.ChromosomeFixer;
import xfuzzy.xfghl.codification.ChromosomeTester;
import xfuzzy.xfghl.codification.DoubleChromosome;
import xfuzzy.xfghl.codification.EncodingSymbols;
import xfuzzy.xfghl.codification.TypeErrorChromosome;
import xfuzzy.xfghl.model.XfghlConfig;

/**
 * Clase encargada de generar una poblacion aleatoriamente
 * @author Alberto David Fernandez Fernandez 
 * */

public class RandomPopulationGenerator extends PopulationGenerator {

	/**
	 * Variable para la generacion de numeros aleatorios
	 * */
	private Random random;
	
	/**
	 * Constructor de la clase
	 * @param seed Semilla del generador de numeros aleatorios
	 * */
	
	public RandomPopulationGenerator(long seed)  {

		super(-1);
		this.random = new Random(seed);
	}
	
	/**
	 * Constructor de la clase
	 * @param seed Semilla del generador de numeros aleatorios
	 * @param sizePopulation Tamaño de la poblacion a generar
	 * */
	
	public RandomPopulationGenerator(long seed, int sizePopulation)  {
		
		super(sizePopulation);
		this.random = new Random(seed);
	}
	
	public Random getRandom() {
		return random;
	}

	public void setRandom(Random random) {
		this.random = random;
	}
	
	/**
	 * Metodo que genera una poblacion de individuos aleatoria
	 * @param config Configuracion de la herramienta Xfghl
	 * @return Population Poblacion generada
	 * */
	
	public Population generarPoblacion(XfghlConfig config)  {
		
		List<DoubleChromosome> individuos = new ArrayList<DoubleChromosome>();
		List<Integer> variables = null;
		DoubleChromosome nuevo = null;
		int longitud_estructura = config.getnumVarEnt() + (config.getnumVarEnt() - 1);
		int [] nuevas_variables = null;
		char [] nueva_estructura = null;
		int indice = -1;
		// se generan un numero de individuos igual a la poblacion inicial
		for (int index = 0; index < this.size; index++)  {
			 // se crean las variables disponibles
			 variables = new ArrayList<Integer>();
			 for (int i = 0; i < config.getnumVarEnt(); i++)
				  variables.add(new Integer(i));
			 nuevas_variables = new int[config.getnumVarEnt()];
			 // se crea el orden de las variables aleatoriamente
			 for (int index_var = 0; index_var < config.getnumVarEnt(); index_var++)  {
				  indice = this.random.nextInt(variables.size());
				  nuevas_variables[index_var] = variables.remove(indice);
			 }
			 // se crea la estructura con sus partes fijas (duda)
			 nueva_estructura = new char[longitud_estructura];
			 nueva_estructura[0] = EncodingSymbols.moduleSymbol;
			 nueva_estructura[longitud_estructura - 1] = EncodingSymbols.variableSymbol;
			 nueva_estructura[longitud_estructura - 2] = EncodingSymbols.variableSymbol;
			 // las partes no fijas se deciden aleatoriamente
			 double valor = 0.0;
			 for (int index_struc = 1; index_struc < longitud_estructura - 2; index_struc++)  {
				  valor = this.random.nextDouble();
				  if (valor > 0.5)
					  nueva_estructura[index_struc] = EncodingSymbols.moduleSymbol;
				  else
					  nueva_estructura[index_struc] = EncodingSymbols.variableSymbol;
			 }
			 nuevo = new DoubleChromosome(config.getnumVarEnt());
			 nuevo.setEstructura(nueva_estructura);
			 nuevo.setVariables(nuevas_variables);
			 nuevo.setNumModulos(config.getnumVarEnt() - 1);
			 individuos.add(nuevo);
		}
		// se comprueba que todos los cromosomas sean correctos; si no lo son, se reparan
		TypeErrorChromosome error = null;
		for (DoubleChromosome cromosoma : individuos)  {
			 error = ChromosomeTester.isValid(cromosoma); 
			 while (error != null)  {
				 ChromosomeFixer.reparar(error, cromosoma, config);
				 error = ChromosomeTester.isValid(cromosoma);
			 }
		}
		
		return new Population(individuos);
	}
}
